package com.allwees.support.marketing.handler;

import lombok.Getter;
import lombok.ToString;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;

import java.math.BigDecimal;
import java.util.Map;
import java.util.function.Function;

/**
 * @Author Daniel
 * @Version 1.0.0
 * @Description
 * @CreateTime 2020/9/2 15:05
 */
@ToString
class PriceRuleHolder {

    private static volatile PriceRuleHolder defaultRule;

    /**
     * 价格区间最小值(含)
     */
    @Getter
    private BigDecimal minPrice;
    /**
     * 价格区间最大值(不含)
     */
    private BigDecimal maxPrice;
    /**
     * 满足本价格区间后的价格计算器(价格加一个值或者有一个涨幅)
     */
    private Function<BigDecimal,BigDecimal> calculator;

    /**
     * minPrice应用了calculator以后的价格
     */
    BigDecimal ominPrice;

    /**
     * maxPrice应用了calculator以后的价格
     */
    BigDecimal omaxPrice;

    /**
     * 如果商品加价以后的价格(p)在[ominPrice,omaxPrice)范围内，则对p进行还原运算(parser是calculator的逆运算)
     */
    Function<BigDecimal,BigDecimal> parser;

    public static PriceRuleHolder getDefault(){
        if (defaultRule == null) {
            synchronized (PriceRuleHolder.class) {
                if (defaultRule == null) {
                    defaultRule = new PriceRuleHolder();
                    defaultRule.calculator = Function.identity();
                    defaultRule.parser = Function.identity();
                }
            }
        }
        return defaultRule;
    }

    private PriceRuleHolder(){}

    public PriceRuleHolder(Map.Entry<String, Object> entry){
        String[] prices = StringUtils.split(entry.getKey(), ',');
        this.minPrice = new BigDecimal(prices[0]);
        this.maxPrice = new BigDecimal(prices[1]);
        String value = entry.getValue().toString();
        calculator = price -> {
            if (NumberUtils.isParsable(value)) {
                return price.add(new BigDecimal(value));
            }
            String substring = value.substring(0, value.length() - 1);
            BigDecimal percentage = new BigDecimal(substring.trim());
            percentage = percentage.movePointLeft(2);
            return price.multiply(percentage.add(BigDecimal.ONE)).stripTrailingZeros();
        };

        parser = price -> {
            if (NumberUtils.isParsable(value)) {
                return price.subtract(new BigDecimal(value));
            }
            String substring = value.substring(0, value.length() - 1);
            BigDecimal percentage = new BigDecimal(substring.trim());
            percentage = percentage.movePointLeft(2);
            return price.divide(percentage.add(BigDecimal.ONE),4,BigDecimal.ROUND_DOWN).stripTrailingZeros();
        };

        ominPrice = calculator.apply(minPrice);
        omaxPrice = calculator.apply(maxPrice);
    }

    public boolean match(BigDecimal price){
        return price.compareTo(minPrice) >= 0 && price.compareTo(maxPrice) < 0;
    }

    public BigDecimal applyRule(BigDecimal price){
        return this.calculator.apply(price);
    }
}

